package com.cmft.filetransfer.service.impl;

import com.cmft.filetransfer.config.FolderPair;
import com.cmft.filetransfer.config.SftpMultiServerConfig;
import com.cmft.filetransfer.config.SftpServerConfig;
import com.cmft.filetransfer.service.FileTransferService;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

/**
 * 文件传输服务实现类，按yyyyMM格式日期文件夹传输文件
 */
@Slf4j
@Service
public class FileTransferServiceImpl implements FileTransferService {

    private final SftpMultiServerConfig multiServerConfig;
    // 日期格式器：生成yyyyMM格式的文件夹名（如202508）
    private static final DateTimeFormatter DIR_DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyyMM");

    @Autowired
    public FileTransferServiceImpl(SftpMultiServerConfig multiServerConfig) {  // 注入多服务器配置
        this.multiServerConfig = multiServerConfig;
    }

    /**
     * 传输当天所需文件（当月日期文件夹内容 + 根目录非文件夹文件）
     */
    @Override
    public int transferTodayFiles() throws Exception {
        int totalCount = 0;
        // 遍历所有配置的服务器
        for (SftpServerConfig server : multiServerConfig.getServers()) {
            log.info("开始处理服务器: {}:{}", server.getHost(), server.getPort());

            // 1. 确定当前服务器的日期文件夹名（复用原有逻辑）
            String dateDirName = server.getIsLocalDate()
                    ? LocalDate.now().format(DIR_DATE_FORMATTER)
                    : server.getStaticDate();

            // 2. 遍历该服务器的所有文件夹对（核心新增逻辑）
            for (FolderPair folder : server.getFolders()) {
                File sourceDir = new File(folder.getLocalDir());  // 从文件夹对取本地目录
                String targetRootDir = folder.getRemoteDir();     // 从文件夹对取远程目录

                // 校验本地目录（复用原有逻辑）
                if (!sourceDir.exists() || !sourceDir.isDirectory()) {
                    log.warn("本地目录不存在，跳过: {}", sourceDir.getAbsolutePath());
                    continue;
                }

                // 3. 建立当前服务器的SFTP连接（复用原有createSftpChannel，仅修改参数）
                ChannelSftp sftpChannel = createSftpChannel(server);  // 适配多服务器参数
                try {
                    createRemoteDirectory(sftpChannel, targetRootDir);  // 复用目录创建
                    // 传输当前文件夹对的文件（复用原有transferTargetFiles，仅修改参数）
                    int count = transferTargetFiles(sftpChannel, sourceDir, targetRootDir, dateDirName);
                    totalCount += count;
                } finally {
                    // 关闭当前服务器连接（复用原有关闭逻辑）
                    if (sftpChannel != null) {
                        sftpChannel.disconnect();
                        sftpChannel.getSession().disconnect();
                    }
                }
            }
        }
        return totalCount;
    }


    private ChannelSftp createSftpChannel(SftpServerConfig server) throws JSchException {
        JSch jsch = new JSch();
        Session session = jsch.getSession(
                server.getUsername(),  // 从当前服务器取用户名
                server.getHost(),      // 从当前服务器取IP
                server.getPort()       // 从当前服务器取端口
        );
        session.setPassword(server.getPassword());  // 从当前服务器取密码

        java.util.Properties config = new java.util.Properties();
        config.put("StrictHostKeyChecking", "no");
        session.setConfig(config);

        session.connect();
        log.info("已连接到SFTP服务器: {}:{}", server.getHost(), server.getPort());

        Channel channel = session.openChannel("sftp");
        channel.connect();
        return (ChannelSftp) channel;
    }

    /**
     * 核心方法：传输符合条件的文件（根目录非文件夹文件 + 当月日期文件夹内容）
     * @param sftp SFTP通道
     * @param sourceDir 源根目录（/barraData/cpeqty）
     * @param targetRootDir 目标根目录（/home/softadmin/barra/cpeqty）
     * @param currentMonthDirName 当月日期文件夹名（如202508）
     */
    private int transferTargetFiles(ChannelSftp sftp, File sourceDir, String targetRootDir, String currentMonthDirName)
            throws SftpException, IOException {
        int count = 0;

        // 遍历源根目录下的所有文件/文件夹
        File[] files = sourceDir.listFiles();
        if (files == null) {
            log.warn("源目录为空: {}", sourceDir.getAbsolutePath());
            return 0;
        }

        for (File file : files) {
            String fileName = file.getName();

            if (file.isDirectory()) {
                // 情况1：如果是当月日期文件夹（如202508），则递归传输其下所有文件
                if (fileName.equals(currentMonthDirName)) {
                    log.info("开始传输当月日期文件夹: {}", file.getAbsolutePath());
                    // 目标子目录：目标根目录/当月日期文件夹（如/home/softadmin/barra/cpeqty/202508）
                    String targetSubDir = targetRootDir + "/" + fileName;
                    createRemoteDirectory(sftp, targetSubDir);
                    // 递归传输该文件夹内的所有文件
                    count += transferAllFilesInDir(sftp, file, targetSubDir);
                } else {
                    log.debug("跳过非当月日期文件夹: {}", file.getAbsolutePath());
                }
            } else {
                // 情况2：如果是源根目录下的非文件夹文件，直接传输
                String targetFilePath = targetRootDir + "/" + fileName;
                try (FileInputStream fis = new FileInputStream(file)) {
                    sftp.put(fis, targetFilePath);
                    log.info("已传输根目录文件: {} -> {}", file.getAbsolutePath(), targetFilePath);
                    count++;
                } catch (SftpException e) {
                    log.error("根目录文件传输失败: {}", file.getAbsolutePath(), e);
                    throw e;
                }
            }
        }

        return count;
    }

    /**
     * 递归传输指定目录下的所有文件（用于传输当月日期文件夹内的内容）
     * @param sftp SFTP通道
     * @param sourceSubDir 源子目录（如/barraData/cpeqty/202508）
     * @param targetSubDir 目标子目录（如/home/softadmin/barra/cpeqty/202508）
     */
    private int transferAllFilesInDir(ChannelSftp sftp, File sourceSubDir, String targetSubDir)
            throws SftpException, IOException {
        int count = 0;

        File[] files = sourceSubDir.listFiles();
        if (files == null) {
            log.warn("子目录为空: {}", sourceSubDir.getAbsolutePath());
            return 0;
        }

        for (File file : files) {
            String fileName = file.getName();
            String targetPath = targetSubDir + "/" + fileName;

            if (file.isDirectory()) {
                // 递归创建子目录并传输内容（支持多级子目录）
                createRemoteDirectory(sftp, targetPath);
                count += transferAllFilesInDir(sftp, file, targetPath);
            } else {
                // 传输文件
                try (FileInputStream fis = new FileInputStream(file)) {
                    sftp.put(fis, targetPath);
                    log.info("已传输子目录文件: {} -> {}", file.getAbsolutePath(), targetPath);
                    count++;
                } catch (SftpException e) {
                    log.error("子目录文件传输失败: {}", file.getAbsolutePath(), e);
                    throw e;
                }
            }
        }

        return count;
    }

    private void createRemoteDirectory(ChannelSftp sftp, String remoteDir) throws SftpException {
        String[] dirs = remoteDir.split("/");
        String currentDir = "";

        for (String dir : dirs) {
            if (!dir.isEmpty()) {
                currentDir += "/" + dir;
                try {
                    sftp.cd(currentDir);
                } catch (SftpException e) {
                    sftp.mkdir(currentDir);
                    sftp.cd(currentDir);
                }
            }
        }
    }


}
